package com.austin.framework.cacheableExtend.helper;

import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.austin.framework.cacheableExtend.CustomRedisCacheManager;
import com.austin.framework.cacheableExtend.annotation.CustomCacheable;
import com.austin.framework.cacheableExtend.constant.CacheConstant;
import com.austin.framework.cacheableExtend.model.CacheInvocation;
import com.austin.framework.cacheableExtend.model.CacheMetaData;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.data.redis.cache.RedisCacheConfiguration;

import java.time.Duration;
import java.util.Map;

/**
 * 缓存过期时间以及过期时缓存自动刷新核心类
 *
 * @author: austin
 * @since: 2023/2/18 18:39
 */
@Slf4j
@UtilityClass
public class CacheHelper {

    public static CustomRedisCacheManager getCacheManager() {
        return SpringUtil.getBean(CacheConstant.CUSTOM_CACHE_MANAGER, CustomRedisCacheManager.class);
    }

    public static void initExpireTime(CustomCacheable customCacheable) {
        String[] cacheNames = getCacheNames(customCacheable);
        if (ArrayUtil.isNotEmpty(cacheNames)) {
            Map<String, RedisCacheConfiguration> initialCacheConfigurations = getCacheManager().getInitialCacheConfigurations();
            for (String cacheName : cacheNames) {
                //设置过期时间
                RedisCacheConfiguration redisCacheConfiguration =
                        RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(customCacheable.expiredTimeSecond()));
                initialCacheConfigurations.put(cacheName, redisCacheConfiguration);
            }
        }
    }

    public static void initializeCaches() {
        //**初始化缓存，并把缓存的name保存到cacheNames中。设置了过期时间
        getCacheManager().initializeCaches();
        log.info(JSON.toJSONString(getCacheManager().getInitialCacheConfigurations()));
    }

    public static String[] getCacheNames(CustomCacheable customCacheable) {
        String[] cacheNames = customCacheable.cacheNames();
        if (ArrayUtil.isEmpty(cacheNames)) {
            cacheNames = customCacheable.value();
        }
        return cacheNames;
    }


    /**
     * 缓存即将到期主动刷新缓存方法
     *
     * @param cacheName
     */
    public void refreshCache(String cacheName) {
        boolean isMatchCacheName = isMatchCacheName(cacheName);
        if (isMatchCacheName) {
            CacheInvocation cacheInvocation = getCacheManager().getCacheInvocation();
            boolean invocationSuccess;
            Object computed = null;
            try {
                computed = cacheInvocation.invoke();
                invocationSuccess = true;
            } catch (Exception e) {
                invocationSuccess = false;
                log.error("refresh cache fail, {}", e);
            }

            if (invocationSuccess) {
                Cache cache = getCacheManager().getCache(cacheName);
                if (ObjectUtil.isNotEmpty(cache)) {
                    Object cacheKey = cacheInvocation.getMetaData().getKey();
                    cache.put(cacheKey, computed);
                    log.info("refresh cache with cacheName -->【{}】，key--> 【{}】 finished !", cacheName, cacheKey);
                }
            }
        }
    }


    private static boolean isMatchCacheName(String cacheName) {
        CacheInvocation CacheInvocation = getCacheManager().getCacheInvocation();
        if (ObjectUtil.isEmpty(CacheInvocation)) {
            log.warn("CacheInvocation is empty!");
            return false;
        }
        CacheMetaData metaData = CacheInvocation.getMetaData();
        for (String name : metaData.getCacheNames()) {
            if (name.equals(cacheName)) {
                return true;
            }
        }
        return true;
    }

}
